﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using COFE.Core;
using COFE.Core.Filter;
using NUnit.Framework;
using COFE.Core.Profile;

namespace COFE.Data.UnitTest
{
    [TestFixture]
    public class TestDBEntryManager
    {
        #region Constructor

        public static string TestVolumeKey = @"Temp";
        public static string TestVolumePath = @"C:\temp";

        static TestDBEntryManager()
        {
            COFEDBShared.Register(null, true);
            if (DBUserProfile.Exists("TestDBEntryManager"))
                DBUserProfile.Remove("TestDBEntryManager");
            IUserProfile user = DBUserProfile.Create("TestDBEntryManager", "TestDBEntryManager");
            if (COFEShared.VolumeRegistrar.LookupRegisterVolume(TestVolumeKey) == null)
                COFEShared.VolumeRegistrar.RegisterVolume(
                    COFEShared.VolumeRegistrar.ConstructVolume("FSI", TestVolumeKey, TestVolumePath,
                    Core.Profile.VolumeAccessMode.All));

            user.RegisterVolume(TestVolumeKey);
            DummyDBPropertyProvider.EnableDummySecondaryPropertyProvider();
        }

        #endregion

        #region Methods

        private string parsableVolumeKey { get { return "{" + TestVolumeKey + "}"; } }

        void RemoveCache()
        {
            COFEDBShared.DBOperations.UpdateDatabase((context) =>
                {
                    var dbEntry = COFEDBShared.DBEntryManager.LookupEntry(context, COFEShared.AdminUserProfile, parsableVolumeKey);
                    if (dbEntry != null)
                    {
                        var entryId = dbEntry.EntryId;
                        if (dbEntry != null)
                            COFEDBShared.DBEntryManager.RemoveEntry(entryId);
                        Assert.IsNull(COFEDBShared.DBEntryManager.LookupEntry(context, COFEShared.AdminUserProfile, entryId));
                    }
                });
        }

        void AddParentToDatabase()
        {
            var parentEntry = COFEShared.CurrentUserProfile
                .TryParsePath(parsableVolumeKey,
                 EntryConstructionFlags.DefaultWithoutCache | EntryConstructionFlags.LookupIfParseFailed
                );

            Assert.IsNotNull(parentEntry);
            Assert.IsTrue(parentEntry is IInternalDirectoryInfoExA);
            var parentDir = parentEntry as IInternalDirectoryInfoExA;

            COFEDBShared.DBEntryManager.RemoveEntry(parentDir.ParseName);

            COFEDBShared.DBOperations.ReadDatabase(
                (context) => COFEDBShared.DBEntryManager.LookupEntry(context, parentDir.ParseName),
                (context, dbEntry) =>
                {
                    Assert.IsNull(dbEntry);
                });
            var dbEntry1 = COFEDBShared.DBEntryManager.UpdateEntry(parentDir.PrimaryPropertyProvider);
            Assert.IsNotNull(dbEntry1);
            //Assert.AreEqual(0, dbEntry.Children.Count);
        }

        void WriteChildToDatabase()
        {
            var parentEntry = COFEShared.CurrentUserProfile
                .TryParsePath(parsableVolumeKey,
                 EntryConstructionFlags.DefaultWithoutCache | EntryConstructionFlags.LookupIfParseFailed);

            Assert.IsNotNull(parentEntry);
            Assert.IsTrue(parentEntry is IInternalDirectoryInfoExA);
            var parentDir = parentEntry as IInternalDirectoryInfoExA;

            var childrenList = parentDir.EnumerateFSIs<IInternalFileSystemInfoExA>(
                new IEntryFilter[] { },
                new IOptionFilter[] { new SearchOptionOptionFilter(SearchOptionEx.TopDirectoryOnly) },
                Core.Profile.EntryConstructionFlags.DefaultWithoutCache).ToList();

            //Property Provider List
            var childPPList = (from child in childrenList select child.PrimaryPropertyProvider).ToList();

            if (childPPList.Count == 0)
                 COFEDBShared.DBOperations.UpdateDatabase((context) =>
                COFEDBShared.DBEntryManager.UpdateDirectoryIsEmpty(context, parentDir.PrimaryPropertyProvider));
            else 
                COFEDBShared.DBOperations.UpdateDatabase((context) =>
                COFEDBShared.DBEntryManager.UpdateEntry(context, childPPList.ToArray(), true, false));

            COFEDBShared.DBOperations.UpdateDatabase((context) =>
                {
                    var parentDbEntry = COFEDBShared.DBEntryManager.LookupEntry(context, parsableVolumeKey);
                    Assert.IsNotNull(parentDbEntry);
                    Assert.AreEqual(childPPList.Count, parentDbEntry.Children.Count);

                    (parentDbEntry as FolderEntry).LastListTime = DateTime.UtcNow;
                    context.SaveChanges();
                });
        }

        void ListChildFromDatabase()
        {


            var parentDbEntry = COFEDBShared.DBOperations.ReadDatabase((context) =>
                 {
                     var retVal = COFEDBShared.DBEntryManager.LookupEntry(context, parsableVolumeKey);
                     retVal.Children.Load();
                     Assert.IsNotNull(retVal);
                     return retVal;
                 });


            string print = "";
            List<IFileSystemInfo> childrenEntryList = new List<IFileSystemInfo>();
            foreach (var child in parentDbEntry.Children)
            {
                IFileSystemInfo entry = null;
                if (child is FolderEntry)
                    entry = COFEShared.EntryConstructor.CreateDirectory(
                        child.SecondaryVolumeId, new DBCachePropertyProvider(child));
                else
                    entry = COFEShared.EntryConstructor.CreateFile(
                        child.SecondaryVolumeId, new DBCachePropertyProvider(child));

                childrenEntryList.Add(entry);
                print += entry.ParseName.Last();
            }

            Console.WriteLine(childrenEntryList.Count.ToString() + " items listed.");
            Console.WriteLine(print);



        }

        void ListChildFromDatabaseUsingDBDirectoryLister()
        {
            COFEDBShared.DBOperations.ReadDatabase(
                (context) => COFEDBShared.DBEntryManager.LookupEntry(context, parsableVolumeKey),
                (context, parentDbEntry) =>
                {
                    Assert.IsNotNull(parentDbEntry);
                    var parentEntry = COFEShared.EntryConstructor.CreateDirectory(
                                parentDbEntry.SecondaryVolumeId, new DBCachePropertyProvider(parentDbEntry));

                    string print = "";
                    int count = 0;
                    foreach (var subEntry in parentEntry
                        //.EnumerateFSIs<IFileSystemInfo>(
                        //new IEntryFilter[] { new AllEntryFilter() },
                        //new IOptionFilter[] { new SearchOptionOptionFilter(SearchOptionEx.TopDirectoryOnly) },
                        //Core.Profile.EntryConstructionFlags.EnableCache))
                        .EnumerateFileSystemInfos())
                    {
                        print += subEntry.ParseName.Last();
                        count++;
                    }
                    Console.WriteLine(count + " items listed.");
                    Console.WriteLine(print);
                });

        }

        void Benchmark(string name, Action action)
        {
            DateTime startTime = DateTime.UtcNow;
            action.Invoke();
            DateTime endTime = DateTime.UtcNow;
            Console.WriteLine(name + " - " + endTime.Subtract(startTime).TotalSeconds.ToString() + "s");
        }

        [Test]
        public void Test()
        {
            Benchmark("RemoveCache", () => { RemoveCache(); });
            Benchmark("AddParentToDatabase", () => { AddParentToDatabase(); });
            Benchmark("WriteChildToDatabase", () => { WriteChildToDatabase(); });

            Benchmark("ListChildFromDatabase", () => { ListChildFromDatabase(); });
            Benchmark("ListChildFromDatabaseUsingDBDirectoryLister", () => { ListChildFromDatabaseUsingDBDirectoryLister(); });

        }


        #endregion

        #region Data

        #endregion

        #region Public Properties

        #endregion

    }
}
